package vista.objetos;

import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.util.Observer;

import javax.media.opengl.awt.GLJPanel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;

import eventos.EventoEtiquetaDeGraficable;

import logica.persistencia.GraficableConEtiquetaPersistente;
import memento.EstadoGuardable;
import memento.IMemento;

import vista.Tema;
import vista.paneles.hojaDibujo.HojaDeDibujo;
import vista.treeDiagrama.NodoTreeDiagrama;
import vista.treeDiagrama.PopupMenuEditar;
import vista.treeDiagrama.TreeDeDiagrama;

public abstract class GraficableConEtiqueta implements Graficable, Observer, EstadoGuardable {

	private JLabel etiqueta;
	private Point punto;
	private Point offset = new Point();
	private GLJPanel canvas;
	private int escalado = 1;
	private PopupMenuEditar popupMenu;
	
	private DiagramaGraficable  diagrama;
	private NodoTreeDiagrama nodo;
	
	public GraficableConEtiqueta()
	{
		this.diagrama = null;
		this.nodo = null;
		this.etiqueta = new JLabel();
		this.etiqueta.setHorizontalAlignment(SwingConstants.CENTER);
		this.setPunto(new Point());
	}
	
	public void inicializarPosicionPunto(int x, int y) {
		this.punto = new Point(x, y); 
	}
	
	public JLabel getEtiqueta() {
		return this.etiqueta;
	}
	
	public void agregarEventoEtiqueta(HojaDeDibujo hoja)
	{
		if (this.getEtiqueta().getMouseListeners().length != 0)
			return;
		
		EventoEtiquetaDeGraficable evento = this.getEvento(hoja); 
		
		this.getEtiqueta().addMouseListener(evento);
		this.getEtiqueta().addMouseMotionListener(evento);
	}
	
	protected abstract EventoEtiquetaDeGraficable getEvento(HojaDeDibujo hoja);
	
	public Point getPunto() {
		return punto;
	}

	private void setPunto(Point punto) {
		this.punto = punto;
	}
	
	public void agregarseAlCanvas(GLJPanel panel, Font fuente, Color color)
	{
		this.canvas = panel;
		
		this.getEtiqueta().setFont(fuente);
		this.getEtiqueta().setForeground(color);
		
		canvas.add(this.getEtiqueta());
	}
	
	public void setUbicacionEtiqueta(int x, int y) {
		this.getEtiqueta().setLocation(x, y);
	}
	
	public void setUbicacionEtiqueta(Point posicion) {
		this.setUbicacionEtiqueta(posicion.x, posicion.y);
	}
	
	public void dragGraficable(Point desplazamiento)
	{
    	setOffset(desplazamiento);
    	setUbicacionEtiqueta(getEtiqueta().getLocation().x + desplazamiento.x,
    			getEtiqueta().getLocation().y + desplazamiento.y);
  	}
	
	public void setOffset(Point nuevoOffset) {
		offset = new Point (nuevoOffset);
	}
	
	public Point getOffset() {
		return offset;
	}
		
	public void borrarseDeLaHoja() 
	{
		try
		{ 
			if (diagrama.soyElDiagramaActual())
				canvas.remove(this.getEtiqueta());
		} 
		catch (NullPointerException e){ //intenta borrar algo q no está agregado al canvas
			e.printStackTrace();
//			System.out.println("borrando algo que no está en el canvas");
		} 
	}
	
	public GLJPanel getContenedor() {
		return this.canvas;
	}
	
	public abstract GraficableConEtiqueta copiarse(IContenedorDeGraficable contenedor);
	
	public void inicializarPosiciones(){}

	public abstract GraficableConEtiquetaPersistente getGraficableConEtiquetaPersistente();

	public IMemento getMementoGenerico() {
		return this.getMementoEspecializado();
	}
	
	@Override
	public IMemento getMementoEspecializado() {
//		System.out.println(this.getClass() + " Memento de graficable nulo  GrafucableCOnEtiqueta"); 
		return null;
	}
	
	@Override
	public void saveMemento(IMemento memento) {
		memento.cargarMemento();
	}
	
	@Override
	public void eliminarNodo() {
		this.getNodo().eliminarse();		
	}

	public DiagramaGraficable getDiagrama() {
//		try { //TODO O U T
//			System.out.println("Soy: "+this.getObjetoDiagramaDecorado().getNombre());
//		} catch (NoEsObjetoDiagramableException e) {
////			e.printStackTrace();
//		}
//		
//		System.out.println("diag q tnego: " + this.diagrama);

		return diagrama;
	}

	void setDiagrama(DiagramaGraficable diagrama) {
//		try {
//			System.out.println("***********************Seteando diagrama a : "+this.getObjetoDiagramaDecorado().getNombre());
//		} catch (NoEsObjetoDiagramableException e) {
//			// TODO O U T 
////			e.printStackTrace();
//		}
		
//		try {
//			System.out.println("diag seteado: " + diagrama.getDiagrama().getNombre());
//		} catch (NullPointerException ee)
//		{
//			System.out.println("objeto diag null solo en copia debería pasar"); 			// TODO O U T 
//		}

		this.diagrama = diagrama;
	}
		
	public abstract boolean tieneLaEntidad(EntidadGraficable entidadGraficable);

	public abstract boolean sePuedeBorrar(EntidadGraficable entidadGraficable);

	public NodoTreeDiagrama getNodo() {
		return nodo;
	}

	public void setNodo(NodoTreeDiagrama nodo) {
		this.nodo = nodo;
	}
	
	public void setNodo() throws NoEsObjetoNodoException {
		this.nodo = this.getNodoTreeDiagrama();
	}
	
	public void cambiarEscala(int nro) 
	{
		escalarEtiqueta(nro);
		escalarPunto(nro);
		escalarOffset(nro);
		
		this.escalado = nro;
	}

	private void escalarOffset(int nro) 
	{
		int posX, posY;
		
		posX = this.getOffset().getLocation().x * nro / escalado;
		posY = this.getOffset().getLocation().y * nro / escalado;
		
		this.getOffset().setLocation(posX, posY);
	}

	private void escalarPunto(int nro) 
	{
		int posX, posY;
		
		posX = this.getPunto().getLocation().x * nro / escalado;
		posY = this.getPunto().getLocation().y * nro / escalado;
		
		this.getPunto().setLocation(posX, posY);
	}

	private void escalarEtiqueta(int nro) 
	{
		Tema tema = Tema.getInstancia();
		int posX, posY, tamH, tamW, tamLetra;
		Font fuente;
		
    	tamLetra = this.getEtiqueta().getFont().getSize() + 12 * (nro - escalado) ;
    	fuente = tema.getFuenteGral(tamLetra);
		
		posX = this.getEtiqueta().getLocation().x * nro / escalado;
		posY = this.getEtiqueta().getLocation().y * nro / escalado;
		tamH = this.getEtiqueta().getSize().height * nro / escalado;
		tamW = this.getEtiqueta().getSize().width * nro / escalado;
		
		this.getEtiqueta().setBounds(posX, posY, tamW, tamH);
		this.getEtiqueta().setFont(fuente);
	}

	public PopupMenuEditar getPopupMenu() {
		return popupMenu;
	}

	public void setPopupMenu() {
		try {
			this.popupMenu = this.getNodoTreeDiagrama().getPopupMenu();
		} catch (NoEsObjetoNodoException e) {
			e.printStackTrace();
		}
	}

	public void agregarseAlArbol(TreeDeDiagrama arbolDeDiagrama) {
		arbolDeDiagrama.agregarNodoTree(this.getNodo());
		
	}

	public void agregarseAlDiagrama(DiagramaGraficable diagramaGraficable) {
		this.setDiagrama(diagramaGraficable);	
		diagramaGraficable.getGraficables().add(this);
	}
	
	public void borrarseDelDiagrama() {}
	
	public void escucharEventoEditar(JFrame ventanaPadre)
	{
		PopupMenuEditar popup = this.getPopupMenu();
		
		if (popup != null)
			popup.escucharEventoEditar(this.getEventoEditarGraficable(ventanaPadre));
	}
	
	public void nodoEscucharEventoEditar(JFrame ventanaPadre)
	{
		NodoTreeDiagrama nodo = this.getNodo();
		
		if (nodo != null)
			nodo.getPopupMenu().escucharEventoEditar(this.getEventoEditarGraficable(ventanaPadre));
	}

	public void eliminarEntidad(EntidadGraficable entidadGraficable) throws GraficableException {}
}